package com.zzzy.sys.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zzzy.common.exception.WarningException;
import com.zzzy.common.util.AssertUtil;
import com.zzzy.common.util.CglibBeanCopierUtil;
import com.zzzy.common.vo.PageResult;
import com.zzzy.framework.common.enums.sys.DataScopeEnum;
import com.zzzy.framework.core.mybatis.query.LambdaQueryWrapperE;
import com.zzzy.framework.dto.DataPermissionDto;
import com.zzzy.sys.dao.entity.*;
import com.zzzy.sys.dao.mapper.RoleMapper;
import com.zzzy.sys.dao.mapper.UserRoleMapper;
import com.zzzy.sys.vo.role.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 角色信息表 服务实现类
 *
 * @author fc
 * @since 2024-04-19
 */
@Service
public class RoleService extends ServiceImpl<RoleMapper, Role> {

    @Resource
    private MenuService menuService;
    @Resource
    private RoleMenuService roleMenuService;
    @Resource
    private UserRoleMapper userRoleMapper;
    @Resource
    private RoleDeptService roleDeptService;
    @Resource
    private UserService userService;

    public PageResult<Role> getRolePage(RolePageReq queryReq) {
        LambdaQueryWrapperE<Role> queryWrapperE = new LambdaQueryWrapperE<Role>()
                .likeIfPresent(Role::getName, queryReq.getName())
                .orderByAsc(Role::getSort);
        return baseMapper.selectPage(queryReq, queryWrapperE);
    }

    public void addRole(RoleAddReq addReq) {
        Role roleByName = getRoleByName(addReq.getName());
        AssertUtil.isNull(roleByName, "角色名称已存在");
        Role role = CglibBeanCopierUtil.copy(addReq, Role.class);
        role.setCreateTime(LocalDateTime.now());
        role.setDataScope(DataScopeEnum.SELF.getValue());
        baseMapper.insert(role);
    }

    public Role getRoleByName(String roleName) {
        return baseMapper.selectOne(new LambdaQueryWrapper<Role>().eq(Role::getName, roleName));
    }

    public Role getRoleById(Long id) {
        Role role = getById(id);
        AssertUtil.nonNull(role, "角色不存在");
        return role;
    }

    public void updateById(RoleUpdateReq updateReq) {
        Role roleByName = getRoleByName(updateReq.getName());
        if (Objects.nonNull(roleByName) && !updateReq.getId().equals(roleByName.getId())){
            throw new WarningException("角色名称已存在");
        }
        Role role = getRoleById(updateReq.getId());
        CglibBeanCopierUtil.copy(updateReq, role);
        role.setUpdateTime(LocalDateTime.now());
        updateById(role);
    }

    /**
     * 角色菜单变动
     */
    @Transactional
    public void operateMenu(RoleMenuOperateReq operateReq) {
        Map<Long, Long> existsMenuIdMap = menuService.getMenuListByRoleId(operateReq.getId()).stream().map(Menu::getId)
                .collect(Collectors.toMap(id-> id, id ->id));
        // 计算新增和删除的菜单ID
        List<Long> menuIdList = CollectionUtils.isEmpty(operateReq.getMenuIds()) ? Collections.emptyList() : operateReq.getMenuIds();
        Map<Long, Long> operateMenuIdMap = menuIdList.stream().collect(Collectors.toMap(id -> id, id -> id));
        List<Long> createMenuIdList = operateMenuIdMap.values().stream().filter(id -> Objects.isNull(existsMenuIdMap.get(id))).collect(Collectors.toList());
        List<Long> deleteMenuIdList = existsMenuIdMap.values().stream().filter(id -> Objects.isNull(operateMenuIdMap.get(id))).collect(Collectors.toList());
        // 执行新增和删除
        if (!CollectionUtils.isEmpty(createMenuIdList)) {
            List<RoleMenu> roleMenuList = createMenuIdList.stream().map(menuId -> {
                RoleMenu roleMenu = new RoleMenu();
                roleMenu.setMenuId(menuId);
                roleMenu.setRoleId(operateReq.getId());
                return roleMenu;
            }).collect(Collectors.toList());
            roleMenuService.saveBatch(roleMenuList);
        }
        if (!CollectionUtils.isEmpty(deleteMenuIdList)) {
            LambdaQueryWrapper<RoleMenu> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(RoleMenu::getRoleId, operateReq.getId())
                    .in(RoleMenu::getMenuId, deleteMenuIdList);
            roleMenuService.remove(wrapper);
        }
    }

    public List<Role> getRoleListByUserId(Long userId) {
        return baseMapper.selectRoleListByUserId(userId);
    }

    @Transactional
    public void deleteById(Long id) {
        Role role = getRoleById(id);
        Long userRoleCount = userRoleMapper.selectCount(new LambdaQueryWrapper<UserRole>().eq(UserRole::getRoleId, role.getId()));
        AssertUtil.isTrue(userRoleCount == 0, "角色已分配用户,不能删除,请先修改用户角色");
        // 删除角色与菜单关联
        roleMenuService.remove(new LambdaQueryWrapper<RoleMenu>().eq(RoleMenu::getRoleId, id));
        // 删除角色与部门关联
        roleDeptService.remove(new LambdaQueryWrapper<RoleDept>().eq(RoleDept::getRoleId, role.getId()));
        removeById(id);
    }

    /**
     * 修改角色数据权限
     */
    @Transactional
    public void operateDataScope(RoleDataScopeReq dataScopeReq) {
        if (DataScopeEnum.DEPT_CUSTOM.getValue().equals(dataScopeReq.getDataScope())
                && CollectionUtils.isEmpty(dataScopeReq.getDataScopeDeptIds())){
            throw new WarningException("指定部门数据权限 则部门不能为空");
        }
        Role role = getRoleById(dataScopeReq.getId());
        role.setDataScope(dataScopeReq.getDataScope());
        role.setUpdateTime(LocalDateTime.now());
        updateById(role);
        roleDeptService.remove(new LambdaQueryWrapper<RoleDept>().eq(RoleDept::getRoleId, role.getId()));
        List<Long> dataScopeDeptIdList = dataScopeReq.getDataScopeDeptIds();
        if (!CollectionUtils.isEmpty(dataScopeDeptIdList)){
            List<RoleDept> roleMenuList = dataScopeDeptIdList.stream().map(deptId -> {
                RoleDept roleDept = new RoleDept();
                roleDept.setDeptId(deptId);
                roleDept.setRoleId(role.getId());
                return roleDept;
            }).collect(Collectors.toList());
            roleDeptService.saveBatch(roleMenuList);
        }
    }

    /**
     * 通过用户id获取数据权限
     */
    public DataPermissionDto getDataPermissionDto(Long userId) {
        User user = userService.getUserById(userId);
        List<Role> roleList = getRoleListByUserId(userId);
        if (CollectionUtils.isEmpty(roleList)){
            new DataPermissionDto(DataScopeEnum.SELF.getValue());
        }
        Map<Integer, List<Role>> dataScopeRoleMap = getRoleListByUserId(userId).stream().collect(Collectors.groupingBy(Role::getDataScope));
        Set<Long> userIdSet = new HashSet<>();
        userIdSet.add(userId);
        Integer dataScopeResult = null;
        for (Map.Entry<Integer, List<Role>> entry : dataScopeRoleMap.entrySet()) {
            Integer dataScope = entry.getKey();
            if (Objects.isNull(dataScopeResult) || dataScope < dataScopeResult){
                dataScopeResult = dataScope;
            }
            List<Role> dataRoleList = entry.getValue();
            if (DataScopeEnum.ALL.getValue().equals(dataScope)){
                return new DataPermissionDto(DataScopeEnum.ALL.getValue());
            } else if (DataScopeEnum.DEPT_CUSTOM.getValue().equals(dataScope)){
                //指定部门权限
                for (Role role : dataRoleList) {
                    List<Long> userIdList = baseMapper.selectCustomDeptUserListByRoleId(role.getId());
                    userIdSet.addAll(userIdList);
                }
            } else if (DataScopeEnum.DEPT_ONLY.getValue().equals(dataScope)){
                //本部门权限
                List<Long> userIdList = userService.getUserListByDeptId(user.getDeptId()).stream().map(User::getId).collect(Collectors.toList());
                userIdSet.addAll(userIdList);
            } else if (DataScopeEnum.DEPT_AND_CHILD.getValue().equals(dataScope)){
                //本部门权限及子部门权限
                List<User> userList = userService.getDeptAndChildDeptUserListByParentDeptId(user.getDeptId());
                userIdSet.addAll(userList.stream().map(User::getId).collect(Collectors.toList()));
            } else {
                //本人权限,或角色未设置数据权限
                userIdSet.add(userId);
            }
        }
        return new DataPermissionDto(dataScopeResult, userIdSet);
    }

    public List<RoleDept> getDataDeptIdListByRoleId(Long id) {
        return roleDeptService.list(new LambdaQueryWrapper<RoleDept>().eq(RoleDept::getRoleId, id));
    }
}
